home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / mg2a_src.zip / DISPLAY.C < prev    next >
C/C++ Source or Header  |  1991-02-16  |  24KB  |  885 lines

  1. /*
  2.  * The functions in this file handle redisplay. The
  3.  * redisplay system knows almost nothing about the editing
  4.  * process; the editing functions do, however, set some
  5.  * hints to eliminate a lot of the grinding. There is more
  6.  * that can be done; the "vtputc" interface is a real
  7.  * pig. Two conditional compilation flags; the GOSLING
  8.  * flag enables dynamic programming redisplay, using the
  9.  * algorithm published by Jim Gosling in SIGOA. The MEMMAP
  10.  * changes things around for memory mapped video. With
  11.  * both off, the terminal is a VT52.
  12.  */
  13. #include    "def.h"
  14. #include    "kbd.h"
  15.  
  16. /*
  17.  * You can change these back to the types
  18.  * implied by the name if you get tight for space. If you
  19.  * make both of them "int" you get better code on the VAX.
  20.  * They do nothing if this is not Gosling redisplay, except
  21.  * for change the size of a structure that isn't used.
  22.  * A bit of a cheat.
  23.  */
  24. /* These defines really belong in sysdef.h */
  25. #ifndef XCHAR
  26. #  define    XCHAR    int
  27. #  define    XSHORT    int
  28. #endif
  29.  
  30. #ifdef    STANDOUT_GLITCH
  31. extern int SG;                /* number of standout glitches    */
  32. #endif
  33.  
  34. /*
  35.  * A video structure always holds
  36.  * an array of characters whose length is equal to
  37.  * the longest line possible. Only some of this is
  38.  * used if "ncol" isn't the same as "NCOL".
  39.  */
  40. typedef struct    {
  41.     short    v_hash;            /* Hash code, for compares.    */
  42.     short    v_flag;            /* Flag word.            */
  43.     short    v_color;        /* Color of the line.        */
  44.     XSHORT    v_cost;            /* Cost of display.        */
  45.     char    v_text[NCOL];        /* The actual characters.    */
  46. }    VIDEO;
  47.  
  48. #define VFCHG    0x0001            /* Changed.            */
  49. #define VFHBAD    0x0002            /* Hash and cost are bad.    */
  50. #define VFEXT    0x0004            /* extended line (beond ncol)    */
  51.  
  52. /*
  53.  * SCORE structures hold the optimal
  54.  * trace trajectory, and the cost of redisplay, when
  55.  * the dynamic programming redisplay code is used.
  56.  * If no fancy redisplay, this isn't used. The trace index
  57.  * fields can be "char", and the score a "short", but
  58.  * this makes the code worse on the VAX.
  59.  */
  60. typedef struct    {
  61.     XCHAR    s_itrace;        /* "i" index for track back.    */
  62.     XCHAR    s_jtrace;        /* "j" index for trace back.    */
  63.     XSHORT    s_cost;            /* Display cost.        */
  64. }    SCORE;
  65.  
  66. int    sgarbf    = TRUE;            /* TRUE if screen is garbage.    */
  67. int    vtrow    = 0;            /* Virtual cursor row.        */
  68. int    vtcol    = 0;            /* Virtual cursor column.    */
  69. int    tthue    = CNONE;        /* Current color.        */
  70. int    ttrow    = HUGE;            /* Physical cursor row.        */
  71. int    ttcol    = HUGE;            /* Physical cursor column.    */
  72. int    tttop    = HUGE;            /* Top of scroll region.    */
  73. int    ttbot    = HUGE;            /* Bottom of scroll region.    */
  74. int    lbound    = 0;            /* leftmost bound of the current line */
  75.                     /* being displayed        */
  76.  
  77. VIDEO    *vscreen[NROW-1];        /* Edge vector, virtual.    */
  78. VIDEO    *pscreen[NROW-1];        /* Edge vector, physical.    */
  79. VIDEO    video[2*(NROW-1)];        /* Actual screen data.        */
  80. VIDEO    blanks;                /* Blank line image.        */
  81.  
  82. /*
  83.  * Some predeclerations to make ANSI compilers happy
  84.  */
  85. VOID    vtinit();
  86. VOID    vttidy();
  87. VOID    vtmove();
  88. VOID    vtputc();
  89. VOID    vtpute();
  90. VOID    vteeol();
  91. VOID    update();
  92. VOID    updext();
  93. VOID    ucopy();
  94. VOID    uline();
  95. VOID    modeline();
  96. VOID    hash();
  97. VOID    setscores();
  98. VOID    traceback();
  99.  
  100. #ifdef    GOSLING
  101. /*
  102.  * This matrix is written as an array because
  103.  * we do funny things in the "setscores" routine, which
  104.  * is very compute intensive, to make the subscripts go away.
  105.  * It would be "SCORE    score[NROW][NROW]" in old speak.
  106.  * Look at "setscores" to understand what is up.
  107.  */
  108. SCORE    score[NROW*NROW];
  109. #endif
  110.  
  111. /*
  112.  * Initialize the data structures used
  113.  * by the display code. The edge vectors used
  114.  * to access the screens are set up. The operating
  115.  * system's terminal I/O channel is set up. Fill the
  116.  * "blanks" array with ASCII blanks. The rest is done
  117.  * at compile time. The original window is marked
  118.  * as needing full update, and the physical screen
  119.  * is marked as garbage, so all the right stuff happens
  120.  * on the first call to redisplay.
  121.  */
  122. VOID
  123. vtinit() {
  124.     register VIDEO    *vp;
  125.     register int    i;
  126.  
  127.     ttopen();
  128.     ttinit();
  129.     vp = &video[0];
  130.     for (i=0; i<NROW-1; ++i) {
  131.         vscreen[i] = vp;
  132.         ++vp;
  133.         pscreen[i] = vp;
  134.         ++vp;
  135.     }
  136.     blanks.v_color = CTEXT;
  137.     for (i=0; i<NCOL; ++i)
  138.         blanks.v_text[i] = ' ';
  139. }
  140.  
  141. /*
  142.  * Tidy up the virtual display system
  143.  * in anticipation of a return back to the host
  144.  * operating system. Right now all we do is position
  145.  * the cursor to the last line, erase the line, and
  146.  * close the terminal channel.
  147.  */
  148. VOID
  149. vttidy() {
  150.     ttcolor(CTEXT);
  151.     ttnowindow();                /* No scroll window.    */
  152.     ttmove(nrow-1, 0);            /* Echo line.        */
  153.     tteeol();
  154.     tttidy();
  155.     ttflush();
  156.     ttclose();
  157. }
  158.  
  159. /*
  160.  * Move the virtual cursor to an origin
  161.  * 0 spot on the virtual display screen. I could
  162.  * store the column as a character pointer to the spot
  163.  * on the line, which would make "vtputc" a little bit
  164.  * more efficient. No checking for errors.
  165.  */
  166. VOID
  167. vtmove(row, col) {
  168.     vtrow = row;
  169.     vtcol = col;
  170. }
  171.  
  172. /*
  173.  * Write a character to the virtual display,
  174.  * dealing with long lines and the display of unprintable
  175.  * things like control characters. Also expand tabs every 8
  176.  * columns. This code only puts printing characters into
  177.  * the virtual display image. Special care must be taken when
  178.  * expanding tabs. On a screen whose width is not a multiple
  179.  * of 8, it is possible for the virtual cursor to hit the
  180.  * right margin before the next tab stop is reached. This
  181.  * makes the tab code loop if you are not careful.
  182.  * Three guesses how we found this.
  183.  */
  184. VOID
  185. vtputc(c) register int c; {
  186.     register VIDEO    *vp;
  187.  
  188.     vp = vscreen[vtrow];
  189.     if (vtcol >= ncol)
  190.         vp->v_text[ncol-1] = '$';
  191.     else if (c == '\t'
  192. #ifdef    NOTAB
  193.         && !(curbp->b_flag & BFNOTAB)
  194. #endif
  195.         ) {
  196.         do {
  197.             vtputc(' ');
  198.         } while (vtcol<ncol && (vtcol&0x07)!=0);
  199.     } else if (ISCTRL(c)) {
  200.         vtputc('^');
  201.         vtputc(CCHR(c));
  202.     } else
  203.         vp->v_text[vtcol++] = c;
  204. }
  205.  
  206. /* Put a character to the virtual screen in an extended line.  If we are
  207.  * not yet on left edge, don't print it yet.  Check for overflow on
  208.  * the right margin.
  209.  */
  210. VOID
  211. vtpute(c)
  212. int c;
  213. {
  214.     register VIDEO    *vp;
  215.  
  216.     vp = vscreen[vtrow];
  217.  
  218.     if (vtcol >= ncol) vp->v_text[ncol - 1] = '$';
  219.     else if (c == '\t'
  220. #ifdef    NOTAB
  221.                && !(curbp->b_flag & BFNOTAB)
  222. #endif
  223.                       ) {
  224.     do {
  225.         vtpute(' ');
  226.     }
  227.     while (((vtcol + lbound)&0x07) != 0 && vtcol < ncol);
  228.     } else if (ISCTRL(c) != FALSE) {
  229.     vtpute('^');
  230.     vtpute(CCHR(c));
  231.     } else {
  232.     if (vtcol >= 0) vp->v_text[vtcol] = c;
  233.     ++vtcol;
  234.     }
  235. }
  236.  
  237. /* Erase from the end of the
  238.  * software cursor to the end of the
  239.  * line on which the software cursor is
  240.  * located. The display routines will decide
  241.  * if a hardware erase to end of line command
  242.  * should be used to display this.
  243.  */
  244. VOID
  245. vteeol() {
  246.     register VIDEO    *vp;
  247.  
  248.     vp = vscreen[vtrow];
  249.     while (vtcol < ncol)
  250.         vp->v_text[vtcol++] = ' ';
  251. }
  252.  
  253. /*
  254.  * Make sure that the display is
  255.  * right. This is a three part process. First,
  256.  * scan through all of the windows looking for dirty
  257.  * ones. Check the framing, and refresh the screen.
  258.  * Second, make sure that "currow" and "curcol" are
  259.  * correct for the current window. Third, make the
  260.  * virtual and physical screens the same.
  261.  */
  262. VOID
  263. update() {
  264.     register LINE    *lp;
  265.     register WINDOW *wp;
  266.     register VIDEO    *vp1;
  267.     VIDEO        *vp2;
  268.     register int    i;
  269.     register int    j;
  270.     register int    c;
  271.     register int    hflag;
  272.     register int    currow;
  273.     register int    curcol;
  274.     register int    offs;
  275.     register int    size;
  276.     VOID traceback ();
  277.     VOID uline ();
  278.  
  279.     if (typeahead()) return;
  280.     if (sgarbf) {                /* must update everything */
  281.         wp = wheadp;
  282.         while(wp != NULL) {
  283.             wp->w_flag |= WFMODE | WFHARD;
  284.             wp = wp->w_wndp;
  285.         }
  286.     }
  287.     hflag = FALSE;                /* Not hard.        */
  288.     wp = wheadp;
  289.     while (wp != NULL) {
  290.         if (wp->w_flag != 0) {        /* Need update.        */
  291.             if ((wp->w_flag&WFFORCE) == 0) {
  292.                 lp = wp->w_linep;
  293.                 for (i=0; i<wp->w_ntrows; ++i) {
  294.                     if (lp == wp->w_dotp)
  295.                         goto out;
  296.                     if (lp == wp->w_bufp->b_linep)
  297.                         break;
  298.                     lp = lforw(lp);
  299.                 }
  300.             }
  301.             i = wp->w_force;    /* Reframe this one.    */
  302.             if (i > 0) {
  303.                 --i;
  304.                 if (i >= wp->w_ntrows)
  305.                     i = wp->w_ntrows-1;
  306.             } else if (i < 0) {
  307.                 i += wp->w_ntrows;
  308.                 if (i < 0)
  309.                     i = 0;
  310.             } else
  311.                 i = wp->w_ntrows/2;
  312.             lp = wp->w_dotp;
  313.             while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) {
  314.                 --i;
  315.                 lp = lback(lp);
  316.             }
  317.             wp->w_linep = lp;
  318.             wp->w_flag |= WFHARD;    /* Force full.        */
  319.         out:
  320.             lp = wp->w_linep;    /* Try reduced update.    */
  321.             i  = wp->w_toprow;
  322.             if ((wp->w_flag&~WFMODE) == WFEDIT) {
  323.                 while (lp != wp->w_dotp) {
  324.                     ++i;
  325.                     lp = lforw(lp);
  326.                 }
  327.                 vscreen[i]->v_color = CTEXT;
  328.                 vscreen[i]->v_flag |= (VFCHG|VFHBAD);
  329.                 vtmove(i, 0);
  330.                 for (j=0; j<llength(lp); ++j)
  331.                     vtputc(lgetc(lp, j));
  332.                 vteeol();
  333.             } else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0) {
  334.                 hflag = TRUE;
  335.                 while (i < wp->w_toprow+wp->w_ntrows) {
  336.                     vscreen[i]->v_color = CTEXT;
  337.                     vscreen[i]->v_flag |= (VFCHG|VFHBAD);
  338.                     vtmove(i, 0);
  339.                     if (lp != wp->w_bufp->b_linep) {
  340.                         for (j=0; j<llength(lp); ++j)
  341.                             vtputc(lgetc(lp, j));
  342.                         lp = lforw(lp);
  343.                     }
  344.                     vteeol();
  345.                     ++i;
  346.                 }
  347.             }
  348.             if ((wp->w_flag&WFMODE) != 0)
  349.                 modeline(wp);
  350.             wp->w_flag  = 0;
  351.             wp->w_force = 0;
  352.         }
  353.         wp = wp->w_wndp;
  354.     }
  355.     lp = curwp->w_linep;            /* Cursor location.    */
  356.     currow = curwp->w_toprow;
  357.     while (lp != curwp->w_dotp) {
  358.         ++currow;
  359.         lp = lforw(lp);
  360.     }
  361.     curcol = 0;
  362.     i = 0;
  363.     while (i < curwp->w_doto) {
  364.         c = lgetc(lp, i++);
  365.         if (c == '\t'
  366. #ifdef    NOTAB
  367.             && !(curbp->b_flag & BFNOTAB)
  368. #endif
  369.             ) curcol |= 0x07;
  370.         else if (ISCTRL(c) != FALSE)
  371.             ++curcol;
  372.         ++curcol;
  373.     }
  374.     if (curcol >= ncol - 1) {        /* extended line. */
  375.          /* flag we are extended and changed */
  376.         vscreen[currow]->v_flag |= VFEXT | VFCHG;
  377.         updext(currow, curcol);        /* and output extended line */
  378.     } else lbound = 0;            /* not extended line */
  379.  
  380.     /* make sure no lines need to be de-extended because the cursor is
  381.     no longer on them */
  382.  
  383.     wp = wheadp;
  384.  
  385.     while (wp != NULL) {
  386.         lp = wp->w_linep;
  387.         i = wp->w_toprow;
  388.         while (i < wp->w_toprow + wp->w_ntrows) {
  389.         if (vscreen[i]->v_flag & VFEXT) {
  390.             /* always flag extended lines as changed */
  391.             vscreen[i]->v_flag |= VFCHG;
  392.             if ((wp != curwp) || (lp != wp->w_dotp) ||
  393.                 (curcol < ncol - 1)) {
  394.             vtmove(i, 0);
  395.             for (j = 0; j < llength(lp); ++j)
  396.                 vtputc(lgetc(lp, j));
  397.             vteeol();
  398.             /* this line no longer is extended */
  399.             vscreen[i]->v_flag &= ~VFEXT;
  400.             }
  401.         }
  402.         lp = lforw(lp);
  403.         ++i;
  404.         }
  405.         /* if garbaged then fix up mode lines */
  406.         if (sgarbf != FALSE) vscreen[i]->v_flag |= VFCHG;
  407.         /* and onward to the next window */
  408.         wp = wp->w_wndp;
  409.     }
  410.  
  411.     if (sgarbf != FALSE) {            /* Screen is garbage.    */
  412.         sgarbf = FALSE;            /* Erase-page clears    */
  413.         epresf = FALSE;            /* the message area.    */
  414.         tttop  = HUGE;            /* Forget where you set */
  415.         ttbot  = HUGE;            /* scroll region.    */
  416.         tthue  = CNONE;            /* Color unknown.    */
  417.         ttmove(0, 0);
  418.         tteeop();
  419.         for (i=0; i<nrow-1; ++i) {
  420.             uline(i, vscreen[i], &blanks);
  421.             ucopy(vscreen[i], pscreen[i]);
  422.         }
  423.         ttmove(currow, curcol - lbound);
  424.         ttflush();
  425.         return;
  426.     }
  427. #ifdef    GOSLING
  428.     if (hflag != FALSE) {            /* Hard update?        */
  429.         for (i=0; i<nrow-1; ++i) {    /* Compute hash data.    */
  430.             hash(vscreen[i]);
  431.             hash(pscreen[i]);
  432.         }
  433.         offs = 0;            /* Get top match.    */
  434.         while (offs != nrow-1) {
  435.             vp1 = vscreen[offs];
  436.             vp2 = pscreen[offs];
  437.             if (vp1->v_color != vp2->v_color
  438.             ||  vp1->v_hash     != vp2->v_hash)
  439.                 break;
  440.             uline(offs, vp1, vp2);
  441.             ucopy(vp1, vp2);
  442.             ++offs;
  443.         }
  444.         if (offs == nrow-1) {        /* Might get it all.    */
  445.             ttmove(currow, curcol - lbound);
  446.             ttflush();
  447.             return;
  448.         }
  449.         size = nrow-1;            /* Get bottom match.    */
  450.         while (size != offs) {
  451.             vp1 = vscreen[size-1];
  452.             vp2 = pscreen[size-1];
  453.             if (vp1->v_color != vp2->v_color
  454.             ||  vp1->v_hash     != vp2->v_hash)
  455.                 break;
  456.             uline(size-1, vp1, vp2);
  457.             ucopy(vp1, vp2);
  458.             --size;
  459.         }
  460.         if ((size -= offs) == 0)    /* Get screen size.    */
  461.             panic("Illegal screen size in update");
  462.         setscores(offs, size);        /* Do hard update.    */
  463.         traceback(offs, size, size, size);
  464.         for (i=0; i<size; ++i)
  465.             ucopy(vscreen[offs+i], pscreen[offs+i]);
  466.         ttmove(currow, curcol - lbound);
  467.         ttflush();
  468.         return;
  469.     }
  470. #endif
  471.     for (i=0; i<nrow-1; ++i) {        /* Easy update.        */
  472.         vp1 = vscreen[i];
  473.         vp2 = pscreen[i];
  474.         if ((vp1->v_flag&VFCHG) != 0) {
  475.             uline(i, vp1, vp2);
  476.             ucopy(vp1, vp2);
  477.         }
  478.     }
  479.     ttmove(currow, curcol - lbound);
  480.     ttflush();
  481. }
  482.  
  483. /*
  484.  * Update a saved copy of a line,
  485.  * kept in a VIDEO structure. The "vvp" is
  486.  * the one in the "vscreen". The "pvp" is the one
  487.  * in the "pscreen". This is called to make the
  488.  * virtual and physical screens the same when
  489.  * display has done an update.
  490.  */
  491. VOID
  492. ucopy(vvp, pvp) register VIDEO *vvp; register VIDEO *pvp; {
  493.  
  494.     vvp->v_flag &= ~VFCHG;            /* Changes done.    */
  495.     pvp->v_flag  = vvp->v_flag;        /* Update model.    */
  496.     pvp->v_hash  = vvp->v_hash;
  497.     pvp->v_cost  = vvp->v_cost;
  498.     pvp->v_color = vvp->v_color;
  499.     bcopy(vvp->v_text, pvp->v_text, ncol);
  500. }
  501.  
  502. /* updext: update the extended line which the cursor is currently
  503.  * on at a column greater than the terminal width. The line
  504.  * will be scrolled right or left to let the user see where
  505.  * the cursor is
  506.  */
  507. VOID
  508. updext(currow, curcol)
  509. int currow, curcol;
  510. {
  511.     register LINE *lp;            /* pointer to current line */
  512.     register int j;            /* index into line */
  513.  
  514.     /* calculate what column the left bound should be */
  515.     /* (force cursor into middle half of screen) */
  516.     lbound = curcol - (curcol % (ncol>>1)) - (ncol>>2);
  517.     /* scan through the line outputing characters to the virtual screen */
  518.     /* once we reach the left edge */
  519.     vtmove(currow, -lbound);            /* start scanning offscreen */
  520.     lp = curwp->w_dotp;                /* line to output */
  521.     for (j=0; j<llength(lp); ++j)        /* until the end-of-line */
  522.     vtpute(lgetc(lp, j));
  523.     vteeol();                    /* truncate the virtual line */
  524.     vscreen[currow]->v_text[0] = '$';        /* and put a '$' in column 1 */
  525. }
  526.  
  527. /*
  528.  * Update a single line. This routine only
  529.  * uses basic functionality (no insert and delete character,
  530.  * but erase to end of line). The "vvp" points at the VIDEO
  531.  * structure for the line on the virtual screen, and the "pvp"
  532.  * is the same for the physical screen. Avoid erase to end of
  533.  * line when updating CMODE color lines, because of the way that
  534.  * reverse video works on most terminals.
  535.  */
  536. VOID uline(row, vvp, pvp) VIDEO *vvp; VIDEO *pvp; {
  537. #ifdef    MEMMAP
  538.     putline(row+1, 1, &vvp->v_text[0]);
  539. #else
  540.     register char    *cp1;
  541.     register char    *cp2;
  542.     register char    *cp3;
  543.     char        *cp4;
  544.     char        *cp5;
  545.     register int    nbflag;
  546.  
  547.     if (vvp->v_color != pvp->v_color) {    /* Wrong color, do a    */
  548.         ttmove(row, 0);            /* full redraw.        */
  549. #ifdef    STANDOUT_GLITCH
  550.         if (pvp->v_color != CTEXT && SG >= 0) tteeol();
  551. #endif
  552.         ttcolor(vvp->v_color);
  553. #ifdef    STANDOUT_GLITCH
  554.         cp1 = &vvp->v_text[SG > 0 ? SG : 0];
  555.         /* the odd code for SG==0 is to avoid putting the invisable
  556.          * glitch character on the next line.
  557.          * (Hazeltine executive 80 model 30)
  558.          */
  559.         cp2 = &vvp->v_text[ncol - (SG >= 0 ? (SG!=0 ? SG : 1) : 0)];
  560. #else
  561.         cp1 = &vvp->v_text[0];
  562.         cp2 = &vvp->v_text[ncol];
  563. #endif
  564.         while (cp1 != cp2) {
  565.             ttputc(*cp1++);
  566.             ++ttcol;
  567.         }
  568. #ifndef MOVE_STANDOUT
  569.         ttcolor(CTEXT);
  570. #endif
  571.         return;
  572.     }
  573.     cp1 = &vvp->v_text[0];            /* Compute left match.    */
  574.     cp2 = &pvp->v_text[0];
  575.     while (cp1!=&vvp->v_text[ncol] && cp1[0]==cp2[0]) {
  576.         ++cp1;
  577.         ++cp2;
  578.     }
  579.     if (cp1 == &vvp->v_text[ncol])        /* All equal.        */
  580.         return;
  581.     nbflag = FALSE;
  582.     cp3 = &vvp->v_text[ncol];        /* Compute right match. */
  583.     cp4 = &pvp->v_text[ncol];
  584.     while (cp3[-1] == cp4[-1]) {
  585.         --cp3;
  586.         --cp4;
  587.         if (cp3[0] != ' ')        /* Note non-blanks in    */
  588.             nbflag = TRUE;        /* the right match.    */
  589.     }
  590.     cp5 = cp3;                /* Is erase good?    */
  591.     if (nbflag==FALSE && vvp->v_color==CTEXT) {
  592.         while (cp5!=cp1 && cp5[-1]==' ')
  593.             --cp5;
  594.         /* Alcyon hack */
  595.         if ((int)(cp3-cp5) <= tceeol)
  596.             cp5 = cp3;
  597.     }
  598.     /* Alcyon hack */
  599.     ttmove(row, (int)(cp1-&vvp->v_text[0]));
  600. #ifdef    STANDOUT_GLITCH
  601.     if (vvp->v_color != CTEXT && SG > 0) {
  602.         if(cp1 < &vvp->v_text[SG]) cp1 = &vvp->v_text[SG];
  603.         if(cp5 > &vvp->v_text[ncol-SG]) cp5 = &vvp->v_text[ncol-SG];
  604.     } else if (SG < 0)
  605. #endif
  606.         ttcolor(vvp->v_color);
  607.     while (cp1 != cp5) {
  608.         ttputc(*cp1++);
  609.         ++ttcol;
  610.     }
  611.     if (cp5 != cp3)                /* Do erase.        */
  612.         tteeol();
  613. #endif
  614. }
  615.  
  616. /*
  617.  * Redisplay the mode line for
  618.  * the window pointed to by the "wp".
  619.  * This is the only routine that has any idea
  620.  * of how the modeline is formatted. You can
  621.  * change the modeline format by hacking at
  622.  * this routine. Called by "update" any time
  623.  * there is a dirty window.
  624.  * Note that if STANDOUT_GLITCH is defined, first and last SG characters
  625.  * may never be seen.
  626.  */
  627. VOID
  628. modeline(wp) register WINDOW *wp; {
  629.     register int    n;
  630.     register BUFFER *bp;
  631.     int    mode;
  632.  
  633.     n = wp->w_toprow+wp->w_ntrows;        /* Location.        */
  634.     vscreen[n]->v_color = CMODE;        /* Mode line color.    */
  635.     vscreen[n]->v_flag |= (VFCHG|VFHBAD);    /* Recompute, display.    */
  636.     vtmove(n, 0);                /* Seek to right line.    */
  637.     bp = wp->w_bufp;
  638.     vtputc('-'); vtputc('-');
  639.     if ((bp->b_flag&BFCHG) != 0) {        /* "*" if changed.    */
  640.         vtputc('*'); vtputc('*');
  641.     } else {
  642.         vtputc('-'); vtputc('-');
  643.     }
  644.     vtputc('-');
  645.     n  = 5;
  646.     n += vtputs("Mg: ");
  647.     if (bp->b_bname[0] != '\0')
  648.         n += vtputs(&(bp->b_bname[0]));
  649.     while (n < 42) {            /* Pad out with blanks    */
  650.         vtputc(' ');
  651.         ++n;
  652.     }
  653.     vtputc('(');
  654.     ++n;
  655.     for(mode=0;;) {
  656.         n += vtputs(bp->b_modes[mode]->p_name);
  657.         if(++mode > bp->b_nmodes) break;
  658.         vtputc('-');
  659.         ++n;
  660.     }
  661.     vtputc(')');
  662.     ++n;
  663.     while (n < ncol) {            /* Pad out.        */
  664.         vtputc('-');
  665.         ++n;
  666.     }
  667. }
  668. /*
  669.  * output a string to the mode line, report how long it was.
  670.  */
  671. vtputs(s) register char *s; {
  672.     register int n = 0;
  673.  
  674.     while (*s != '\0') {
  675.         vtputc(*s++);
  676.         ++n;
  677.     }
  678.     return n;
  679. }
  680. #ifdef    GOSLING
  681. /*
  682.  * Compute the hash code for
  683.  * the line pointed to by the "vp". Recompute
  684.  * it if necessary. Also set the approximate redisplay
  685.  * cost. The validity of the hash code is marked by
  686.  * a flag bit. The cost understand the advantages
  687.  * of erase to end of line. Tuned for the VAX
  688.  * by Bob McNamara; better than it used to be on
  689.  * just about any machine.
  690.  */
  691. VOID
  692. hash(vp) register VIDEO *vp; {
  693.     register int    i;
  694.     register int    n;
  695.     register char    *s;
  696.  
  697.     if ((vp->v_flag&VFHBAD) != 0) {        /* Hash bad.        */
  698.         s = &vp->v_text[ncol-1];
  699.         for (i=ncol; i!=0; --i, --s)
  700.             if (*s != ' ')
  701.                 break;
  702.         n = ncol-i;            /* Erase cheaper?    */
  703.         if (n > tceeol)
  704.             n = tceeol;
  705.         vp->v_cost = i+n;        /* Bytes + blanks.    */
  706.         for (n=0; i!=0; --i, --s)
  707.             n = (n<<5) + n + *s;
  708.         vp->v_hash = n;            /* Hash code.        */
  709.         vp->v_flag &= ~VFHBAD;        /* Flag as all done.    */
  710.     }
  711. }
  712.  
  713. /*
  714.  * Compute the Insert-Delete
  715.  * cost matrix. The dynamic programming algorithm
  716.  * described by James Gosling is used. This code assumes
  717.  * that the line above the echo line is the last line involved
  718.  * in the scroll region. This is easy to arrange on the VT100
  719.  * because of the scrolling region. The "offs" is the origin 0
  720.  * offset of the first row in the virtual/physical screen that
  721.  * is being updated; the "size" is the length of the chunk of
  722.  * screen being updated. For a full screen update, use offs=0
  723.  * and size=nrow-1.
  724.  *
  725.  * Older versions of this code implemented the score matrix by
  726.  * a two dimensional array of SCORE nodes. This put all kinds of
  727.  * multiply instructions in the code! This version is written to
  728.  * use a linear array and pointers, and contains no multiplication
  729.  * at all. The code has been carefully looked at on the VAX, with
  730.  * only marginal checking on other machines for efficiency. In
  731.  * fact, this has been tuned twice! Bob McNamara tuned it even
  732.  * more for the VAX, which is a big issue for him because of
  733.  * the 66 line X displays.
  734.  *
  735.  * On some machines, replacing the "for (i=1; i<=size; ++i)" with
  736.  * i = 1; do { } while (++i <=size)" will make the code quite a
  737.  * bit better; but it looks ugly.
  738.  */
  739. VOID
  740. setscores(offs, size) {
  741.     register SCORE    *sp;
  742.     SCORE        *sp1;
  743.     register int    tempcost;
  744.     register int    bestcost;
  745.     register int    j;
  746.     register int    i;
  747.     register VIDEO    **vp;
  748.     VIDEO        **pp, **vbase, **pbase;
  749.  
  750.     vbase = &vscreen[offs-1];        /* By hand CSE's.    */
  751.     pbase = &pscreen[offs-1];
  752.     score[0].s_itrace = 0;            /* [0, 0]        */
  753.     score[0].s_jtrace = 0;
  754.     score[0].s_cost      = 0;
  755.     sp = &score[1];                /* Row 0, inserts.    */
  756.     tempcost = 0;
  757.     vp = &vbase[1];
  758.     for (j=1; j<=size; ++j) {
  759.         sp->s_itrace = 0;
  760.         sp->s_jtrace = j-1;
  761.         tempcost += tcinsl;
  762.         tempcost += (*vp)->v_cost;
  763.         sp->s_cost = tempcost;
  764.         ++vp;
  765.         ++sp;
  766.     }
  767.     sp = &score[NROW];            /* Column 0, deletes.    */
  768.     tempcost = 0;
  769.     for (i=1; i<=size; ++i) {
  770.         sp->s_itrace = i-1;
  771.         sp->s_jtrace = 0;
  772.         tempcost  += tcdell;
  773.         sp->s_cost = tempcost;
  774.         sp += NROW;
  775.     }
  776.     sp1 = &score[NROW+1];            /* [1, 1].        */
  777.     pp = &pbase[1];
  778.     for (i=1; i<=size; ++i) {
  779.         sp = sp1;
  780.         vp = &vbase[1];
  781.         for (j=1; j<=size; ++j) {
  782.             sp->s_itrace = i-1;
  783.             sp->s_jtrace = j;
  784.             bestcost = (sp-NROW)->s_cost;
  785.             if (j != size)        /* Cd(A[i])=0 @ Dis.    */
  786.                 bestcost += tcdell;
  787.             tempcost = (sp-1)->s_cost;
  788.             tempcost += (*vp)->v_cost;
  789.             if (i != size)        /* Ci(B[j])=0 @ Dsj.    */
  790.                 tempcost += tcinsl;
  791.             if (tempcost < bestcost) {
  792.                 sp->s_itrace = i;
  793.                 sp->s_jtrace = j-1;
  794.                 bestcost = tempcost;
  795.             }
  796.             tempcost = (sp-NROW-1)->s_cost;
  797.             if ((*pp)->v_color != (*vp)->v_color
  798.             ||  (*pp)->v_hash  != (*vp)->v_hash)
  799.                 tempcost += (*vp)->v_cost;
  800.             if (tempcost < bestcost) {
  801.                 sp->s_itrace = i-1;
  802.                 sp->s_jtrace = j-1;
  803.                 bestcost = tempcost;
  804.             }
  805.             sp->s_cost = bestcost;
  806.             ++sp;            /* Next column.        */
  807.             ++vp;
  808.         }
  809.         ++pp;
  810.         sp1 += NROW;            /* Next row.        */
  811.     }
  812. }
  813.  
  814. /*
  815.  * Trace back through the dynamic programming cost
  816.  * matrix, and update the screen using an optimal sequence
  817.  * of redraws, insert lines, and delete lines. The "offs" is
  818.  * the origin 0 offset of the chunk of the screen we are about to
  819.  * update. The "i" and "j" are always started in the lower right
  820.  * corner of the matrix, and imply the size of the screen.
  821.  * A full screen traceback is called with offs=0 and i=j=nrow-1.
  822.  * There is some do-it-yourself double subscripting here,
  823.  * which is acceptable because this routine is much less compute
  824.  * intensive then the code that builds the score matrix!
  825.  */
  826. VOID traceback(offs, size, i, j) {
  827.     register int    itrace;
  828.     register int    jtrace;
  829.     register int    k;
  830.     register int    ninsl;
  831.     register int    ndraw;
  832.     register int    ndell;
  833.  
  834.     if (i==0 && j==0)            /* End of update.    */
  835.         return;
  836.     itrace = score[(NROW*i) + j].s_itrace;
  837.     jtrace = score[(NROW*i) + j].s_jtrace;
  838.     if (itrace == i) {            /* [i, j-1]        */
  839.         ninsl = 0;            /* Collect inserts.    */
  840.         if (i != size)
  841.             ninsl = 1;
  842.         ndraw = 1;
  843.         while (itrace!=0 || jtrace!=0) {
  844.             if (score[(NROW*itrace) + jtrace].s_itrace != itrace)
  845.                 break;
  846.             jtrace = score[(NROW*itrace) + jtrace].s_jtrace;
  847.             if (i != size)
  848.                 ++ninsl;
  849.             ++ndraw;
  850.         }
  851.         traceback(offs, size, itrace, jtrace);
  852.         if (ninsl != 0) {
  853.             ttcolor(CTEXT);
  854.             ttinsl(offs+j-ninsl, offs+size-1, ninsl);
  855.         }
  856.         do {                /* B[j], A[j] blank.    */
  857.             k = offs+j-ndraw;
  858.             uline(k, vscreen[k], &blanks);
  859.         } while (--ndraw);
  860.         return;
  861.     }
  862.     if (jtrace == j) {            /* [i-1, j]        */
  863.         ndell = 0;            /* Collect deletes.    */
  864.         if (j != size)
  865.             ndell = 1;
  866.         while (itrace!=0 || jtrace!=0) {
  867.             if (score[(NROW*itrace) + jtrace].s_jtrace != jtrace)
  868.                 break;
  869.             itrace = score[(NROW*itrace) + jtrace].s_itrace;
  870.             if (j != size)
  871.                 ++ndell;
  872.         }
  873.         if (ndell != 0) {
  874.             ttcolor(CTEXT);
  875.             ttdell(offs+i-ndell, offs+size-1, ndell);
  876.         }
  877.         traceback(offs, size, itrace, jtrace);
  878.         return;
  879.     }
  880.     traceback(offs, size, itrace, jtrace);
  881.     k = offs+j-1;
  882.     uline(k, vscreen[k], pscreen[offs+i-1]);
  883. }
  884. #endif
  885.